package com.seafood.service.impl;

import com.seafood.dto.LoginResponseDTO;
import com.seafood.dto.UserDTO;
import com.seafood.dto.UserLoginDTO;
import com.seafood.dto.UserRegisterDTO;
import com.seafood.dto.VerifySmsCodeRequestDTO;
import com.seafood.entity.User;
import com.seafood.repository.UserRepository;
import com.seafood.service.SmsVerificationCodeService;
import com.seafood.service.UserService;
import com.seafood.util.JwtUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.format.DateTimeFormatter;

/**
 * 用户服务实现类
 */
@Service
@RequiredArgsConstructor
@Transactional
public class UserServiceImpl implements UserService {
    
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    private final JwtUtil jwtUtil;
    private final SmsVerificationCodeService smsVerificationCodeService;
    
    @Override
    public UserDTO register(UserRegisterDTO registerDTO) {
        // 验证密码确认
        if (!registerDTO.getPassword().equals(registerDTO.getConfirmPassword())) {
            throw new RuntimeException("密码确认不匹配");
        }
        
        // 检查用户名是否已存在
        if (userRepository.existsByUsername(registerDTO.getUsername())) {
            throw new RuntimeException("用户名已存在");
        }
        
        // 检查邮箱是否已存在
        if (userRepository.existsByEmail(registerDTO.getEmail())) {
            throw new RuntimeException("邮箱已被注册");
        }
        
        // 检查手机号是否已存在
        if (userRepository.existsByPhone(registerDTO.getPhone())) {
            throw new RuntimeException("手机号已被注册");
        }
        
        // 验证短信验证码
        VerifySmsCodeRequestDTO smsRequest = new VerifySmsCodeRequestDTO();
        smsRequest.setPhone(registerDTO.getPhone());
        smsRequest.setCode(registerDTO.getSmsCode());
        smsRequest.setCodeType("REGISTER");
        
        if (!smsVerificationCodeService.verifyAndUseCode(smsRequest, null)) {
            throw new RuntimeException("短信验证码验证失败");
        }
        
        // 创建新用户
        User user = new User();
        user.setUsername(registerDTO.getUsername());
        user.setPassword(passwordEncoder.encode(registerDTO.getPassword()));
        user.setEmail(registerDTO.getEmail());
        user.setPhone(registerDTO.getPhone());
        user.setRealName(registerDTO.getRealName());
        user.setCompanyName(registerDTO.getCompanyName());
        user.setAddress(registerDTO.getAddress());
        
        // 设置用户类型
        try {
            user.setUserType(User.UserType.valueOf(registerDTO.getUserType()));
        } catch (IllegalArgumentException e) {
            user.setUserType(User.UserType.INDIVIDUAL);
        }
        
        // 保存用户
        User savedUser = userRepository.save(user);
        
        return convertToDTO(savedUser);
    }
    
    @Override
    public LoginResponseDTO login(UserLoginDTO loginDTO) {
        // 查找用户
        User user = userRepository.findByUsernameOrEmail(loginDTO.getUsernameOrEmail())
                .orElseThrow(() -> new RuntimeException("用户名或密码错误"));
        
        // 检查用户状态
        if (user.getStatus() == User.UserStatus.INACTIVE) {
            throw new RuntimeException("账户已被禁用");
        }
        
        // 验证密码
        if (!passwordEncoder.matches(loginDTO.getPassword(), user.getPassword())) {
            throw new RuntimeException("用户名或密码错误");
        }
        
        // 生成JWT token
        String token = jwtUtil.generateToken(user.getUsername());
        
        // 转换为DTO
        UserDTO userDTO = convertToDTO(user);
        
        return new LoginResponseDTO(token, userDTO);
    }
    
    @Override
    @Transactional(readOnly = true)
    public User findByUsername(String username) {
        return userRepository.findByUsername(username)
                .orElseThrow(() -> new RuntimeException("用户不存在"));
    }
    
    @Override
    @Transactional(readOnly = true)
    public User findByUsernameOrEmail(String usernameOrEmail) {
        return userRepository.findByUsernameOrEmail(usernameOrEmail)
                .orElseThrow(() -> new RuntimeException("用户不存在"));
    }
    
    @Override
    @Transactional(readOnly = true)
    public User findById(Long id) {
        return userRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("用户不存在"));
    }
    
    @Override
    public UserDTO updateUser(Long id, UserDTO userDTO) {
        User user = findById(id);
        
        // 更新可编辑字段
        if (userDTO.getPhone() != null) {
            user.setPhone(userDTO.getPhone());
        }
        if (userDTO.getRealName() != null) {
            user.setRealName(userDTO.getRealName());
        }
        if (userDTO.getCompanyName() != null) {
            user.setCompanyName(userDTO.getCompanyName());
        }
        if (userDTO.getAddress() != null) {
            user.setAddress(userDTO.getAddress());
        }
        if (userDTO.getAvatarUrl() != null) {
            user.setAvatarUrl(userDTO.getAvatarUrl());
        }
        
        User savedUser = userRepository.save(user);
        return convertToDTO(savedUser);
    }
    
    @Override
    @Transactional(readOnly = true)
    public boolean existsByUsername(String username) {
        return userRepository.existsByUsername(username);
    }
    
    @Override
    @Transactional(readOnly = true)
    public boolean existsByEmail(String email) {
        return userRepository.existsByEmail(email);
    }
    
    @Override
    public UserDTO convertToDTO(User user) {
        UserDTO dto = new UserDTO();
        dto.setId(user.getId());
        dto.setUsername(user.getUsername());
        dto.setEmail(user.getEmail());
        dto.setPhone(user.getPhone());
        dto.setRealName(user.getRealName());
        dto.setCompanyName(user.getCompanyName());
        dto.setUserType(user.getUserType().name());
        dto.setStatus(user.getStatus().name());
        dto.setAvatarUrl(user.getAvatarUrl());
        dto.setAddress(user.getAddress());
        
        if (user.getCreatedAt() != null) {
            dto.setCreatedAt(user.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        }
        
        return dto;
    }
}